﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PacmanAI
{
    public delegate TResult Evaluator<TObj,TResult>(TObj obj);

    abstract public class Boolable
    {
        protected abstract bool IsTrue();

        public static implicit operator bool(Boolable r)
        {
            return r.IsTrue();
        }
    }
    
    public class ValueResult<Tobj,Tvalue> 
        where Tvalue : IComparable
    {
        private Tobj _object;

        public Tobj Object
        {
            get { return _object; }
            set { _object = value; }
        }
        private Tvalue _value;

        public Tvalue Value
        {
            get { return _value; }
            set { _value = value; }
        }
        
        public ValueResult(Tobj o, Tvalue v)
        {
            Object = o;
            Value = v;
        }

        
    }

    static public class IEnumerableExt
    {
        public static ValueResult<TObj, TResult> TryFindMax<TObj, TResult>(
            this IEnumerable<TObj> coll,
            TResult minValue,
            Evaluator<TObj,TResult> eval)
            where TResult: IComparable
        {
            var maxV = minValue;
            var cur = new ValueResult<TObj,TResult>(default(TObj) ,minValue);
            foreach (var i in coll)
            {
                var ri = eval(i);
                if (ri.CompareTo(cur.Value) > 0) // ri > cur.Value
                {
                    cur.Object = i;
                    cur.Value = ri;
                }
            }

            return cur;
        }

        public static List<TTarget> Map<TSource, TTarget>(
            this IEnumerable<TSource> source,
            Evaluator<TSource, TTarget> mapFunction)
        {
            var r = new List<TTarget>();
            foreach (var i in source)
                r.Add(mapFunction(i));
            return r;           
        }

        public static TSource FindBest<TSource>(this IEnumerable<TSource> source,
              Comparison<TSource> comp)            
        {
            bool first = true;
            TSource result = default(TSource);
            foreach (var i in source)
            {
                if (first)
                {
                    result = i;
                    first = false;
                }
                else if (comp(i, result) > 0) // result is better than i 
                    result = i;
            }
            return result;
        }

        public static List<TSource> Filter<TSource>(this IEnumerable<TSource> source,
              Predicate<TSource> pred)
        {
            List<TSource> result = new List<TSource>();
            foreach (var i in source)
                if (pred(i))
                    result.Add(i);
            return result;
        }


    }

    public static class IComparableExt
    {
        public static T Minimum<T>(T a, T b)
            where T : IComparable
        {
            if (a.CompareTo(b) < 0) return a;
            return b;
        }
    }


}
